package org.calconnect.icalproofing;

/**
 *	<p>ICalProofingWebService class</p>
 *
 *	<p>Starts the web service, listening for incoming HTTP or HTTPS connections
 *	and routing requests, based on their URLs, to various Resource classes.</p>
 *
 *	<p>System requirements: Requires Java 1.5 or higher.</p>
 *
 *	<p><em>Last checked in by: $Author: aron $ at $Date: 2008-10-27 13:55:56 -0700 (Mon, 27 Oct 2008) $</em></p>
 *
 *	@author Aron Roberts
 *	@version $Revision: 509 $
 */

/*
 * Copyright 2005-2007 Noelios Consulting.
 * 
 * The contents of this file are subject to the terms of the Common Development
 * and Distribution License (the "License"). You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at
 * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL HEADER in each file and
 * include the License file at http://www.opensource.org/licenses/cddl1.txt If
 * applicable, add the following below this CDDL HEADER, with the fields
 * enclosed by brackets "[]" replaced with your own identifying information:
 * Portions Copyright [yyyy] [name of copyright owner]
 */
 
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.FileHandler;

import org.apache.log4j.Logger;

import org.restlet.Application;
import org.restlet.Component;
import org.restlet.Context;
import org.restlet.Restlet;
import org.restlet.Route;
import org.restlet.Router;
import org.restlet.Server;
import org.restlet.data.Protocol;
import org.restlet.resource.Resource;
import org.restlet.service.LogService;
import org.restlet.service.StatusService;
import org.restlet.util.Template;
import org.restlet.util.Variable;

public class ICalProofingWebService extends org.restlet.Application {

	// Class variables

	// Get the name of this class
	final static String CLASSNAME = ICalProofingWebService.class.getName();

	// Create a log4j 'logger' for this class, based on the class name
  //
  // This allows us to identify which log events are coming from the
  // methods of this class
	public static org.apache.log4j.Logger logger = 
		org.apache.log4j.Logger.getLogger( CLASSNAME );

	/////////////////////////////////////////////////////////////////
	/**
	 *	Class constructor (no argument).
	 */
	public ICalProofingWebService() {

		super();

		logger.debug( "In no-argument constructor for " + CLASSNAME + "..." );
				
	}

	/////////////////////////////////////////////////////////////////
	/**
	 *	Class constructor.
	 *
	 *	@param		context  A Context object.
	 */
	public ICalProofingWebService( Context context ) {

		super( context );

		logger.debug("In constructor( Context ) for " + CLASSNAME + "...");
				
	}

	// @todo: remove routes from application if initialization of various
	// repository objects fails.
	
	/////////////////////////////////////////////////////////////////
	/**
	 *	Handle routing of requests by URL.
	 */
	@Override
	public Restlet createRoot() {

	  logger.debug( "In createRoot() ... in class " + CLASSNAME );
	
		Router router = new Router( getContext() );
		Route route = null;


		// ----------------------------------------------------------------------------------
		// ICalendar validators
		// ----------------------------------------------------------------------------------

		// Add routes to handle requests for each iCalendar validator.
		
		// Define route components common to all iCalendar validators:

		// Declare URL parts for identifying a service version.
		// (Currently, this is unused.)
		final String VERSION_BASE_URL = ""; // e.g. "/v2"
		
		
		// ----------------------------------------------------------------------------------
		// iCal4j
		// ----------------------------------------------------------------------------------
		
		final String ICAL4J_BASE_URL = VERSION_BASE_URL + "/ical4j";
		
		// Note: currently the following two URLs are routed to the validator resource,
		// but all requests to them fail with a 4xx error, because no URL from which to
		// retrieve iCalendar data is included in the URL path.
		
		// Route requests to /ical4j and /ical4j/
		route = router.attach( 
			ICAL4J_BASE_URL,
			ICal4jValidatorResource.class );
		route.getTemplate().setMatchingMode( Template.MODE_EQUALS );

		route = router.attach( 
			ICAL4J_BASE_URL + "/",
			ICal4jValidatorResource.class );
		route.getTemplate().setMatchingMode( Template.MODE_EQUALS );

		// Route requests to /ical4j/{url} and /ical4j/{url}/, where {url} is an
		// HTTP URL pointing at iCalendar data (e.g. http://www.example.com/example.ics).
		route = router.attach( 
			ICAL4J_BASE_URL + "/{url}",
			ICal4jValidatorResource.class );
		route.getTemplate().getVariables().put( "url", new Variable( Variable.TYPE_URI_ALL ) );

		router.attach( 
			ICAL4J_BASE_URL + "/{url}/",
			ICal4jValidatorResource.class );
		route.getTemplate().getVariables().put( "url", new Variable( Variable.TYPE_URI_ALL ) );
		

		// ----------------------------------------------------------------------------------
		// VObject
		// ----------------------------------------------------------------------------------
		
		// Placeholder for future addition of routes for validating using the
		// VObject library for Python


		// ----------------------------------------------------------------------------------
		// XML representation of iCalendar
		// ----------------------------------------------------------------------------------
		
		// Placeholder for future addition of routes for validating
		// of an XML-based representation of iCalendar data


		// ----------------------------------------------------------------------------------
		// Default handler for all other URLs
		// ----------------------------------------------------------------------------------

		// @todo Attach a default route to handle requested URLs where no other templates match.
		// In the absence of a custom handler, Restlet is currently using its own default handler.
		// router.attachDefault( {add subclass of Resource.class or an instantiated Restlet here} );


		return router;

	}

	/////////////////////////////////////////////////////////////////

  public static void main( String[] args ) {

		// Display descriptive information about this class

  	System.out.println( CLASSNAME );
  	System.out.println( "$Revision: 509 $" );
  	System.out.println( "$Date: 2008-10-27 13:55:56 -0700 (Mon, 27 Oct 2008) $" );
  	
  	final Protocol DEFAULT_PROTOCOL = Protocol.HTTP;
  	final int DEFAULT_PORT = 15000;
  	
  	Protocol protocol = null;
  	protocol = DEFAULT_PROTOCOL; // or get this from external configuration
  	if ( protocol == null ) {
			logger.fatal( 
				"[ERROR] Attempt to launch service failed: " +
				"could not obtain or recognize protocol." );
			System.exit( 1 ); 
		}
  	
  	int port = 0;
  	port = DEFAULT_PORT; // or get this from external configuration
  	if ( port == 0 ) {
			logger.fatal( 
				"[ERROR] Attempt to launch service failed: " +
				"could not obtain or recognize port." );
			System.exit( 1 );
		}
		
		// Create a new component.
		Component component = new Component();
		
		// Configure access logging for the component.
		// @todo Add this here.

    // Attach a new server to the component.
    component.getServers().add( protocol, port );

		// Attach the application to the component's default host,
		// and give it a protected copy of the parent component's context
		// (logging and other attributes).
		Context context = component.getContext();
		component.getDefaultHost().attach( new ICalProofingWebService( context.createChildContext() ) );
		
		// Attach an error handler (status service) to the component.
		StatusService statusService = (StatusService) new ErrorHandler();
		component.setStatusService( statusService );

		// Start the service.
		try {

			component.start();
			
			logger.info( 
				"Service listening for " 
				+ protocol.toString() +
				" connections on port " +
				StringUtils.intToString( port ) +
				" ..." );

		} catch ( Exception e ) {
			// Examples of error messages from this Exception:
			// "Permission denied"
			logger.fatal( "[ERROR] Attempt to launch service failed: " + e.getMessage() );
			System.exit( 1 );
		}
        
  }

}

